#include "serverwindow.h"
#include "ui_serverwindow.h"

ServerWindow::ServerWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ServerWindow)
{
    ui->setupUi(this);

    //server management
    server = new QTcpServer(this);
    if(!server->listen(QHostAddress::Any, 4000))//listening on all ips available and on port 4000
    {
        //server did not start
        ui->serverState->setText(tr("The server did not start. Reason: <br />") + server->errorString());
    }
    else
    {
        //server started
        ui->serverState->setText(tr("Server started on port <strong>") + QString::number(server->serverPort()) +
                                 tr("</strong>.<br />Waiting for clients..."));
        connect(server, SIGNAL(newConnection()), this, SLOT(newConnexion()));
    }

    messageSize = 0;
    connectedClients = 0;
}

ServerWindow::~ServerWindow()
{
    delete ui;
}

void ServerWindow::newConnexion()
{
    connectedClients++;
    ui->nbConnectedClients->setText(QString::number(connectedClients));

    QTcpSocket *newConnection = server->nextPendingConnection();
    Client *newClient = new Client(newConnection);
    clients << newClient;

    connect(newConnection, SIGNAL(readyRead()), this, SLOT(dataReceived()));
    connect(newConnection, SIGNAL(disconnected()), this, SLOT(clientDisconnect()));
}

void ServerWindow::dataReceived()
{
    //1: we receive a message

    //we determine which client sent the message
    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
    if(socket == 0)//if the sender is not recognised
    {
        return;
    }

    //we search the client in the clients list
    Client* client = findClient(socket);
    if(client == NULL)
    {
        return; //if the client is not found
    }

    QDataStream in(socket);

    //message size reception
    if(client->messageSize == 0)
    {
        if(socket->bytesAvailable() < (int)sizeof(quint16))//test if message sized received
        {
            return;
        }

        in >> client->messageSize;
    }

    //if received data smaller than message size end proc
    if(socket->bytesAvailable() < messageSize)
    {
        return;
    }

    //message received entirely
    QString message;
    in >> message;

    //if client has no nickname, his first message is his nickname
    if(client->GetNickname().isEmpty())
    {
        client->SetNickname(message);
        sendToAllExceptCurrent(client->GetSocket(), tr("<em>") + client->GetNickname() + tr("</em> is now connected"));
        client->SendMessage(AssembleMessage("Welcome "+client->GetNickname()));
    }
    else
    {
        //send message to everybody
        sendToAll(message);
    }

    //reset messageSize
    client->messageSize = 0;
}

void ServerWindow::clientDisconnect()
{
    sendToAll("<em>A client has left.</em>");

    //find which client has left
    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
    if(socket == 0)//if client not found
    {
        return;
    }

    clients.removeOne(findClient(socket));

    socket->deleteLater();

    connectedClients--;
    ui->nbConnectedClients->setText(QString::number(connectedClients));
}

QByteArray ServerWindow::AssembleMessage(QString message)
{
    //packet preparation
    QByteArray packet;
    QDataStream out(&packet, QIODevice::WriteOnly);

    out << (quint16) 0;
    out << message;
    out.device()->seek(0);
    out << (quint16) (packet.size() - sizeof(quint16));

    return packet;
}

void ServerWindow::sendToAll(const QString &message)
{
    //packet preparation
    QByteArray packet;
    QDataStream out(&packet, QIODevice::WriteOnly);

    out << (quint16) 0;
    out << message;
    out.device()->seek(0);
    out << (quint16) (packet.size() - sizeof(quint16));

    //packet sending
    for(int i = 0 ; i < clients.size() ; i++)
    {
        clients[i]->SendMessage(packet);
    }

}

void ServerWindow::sendToAllExceptCurrent(QTcpSocket *socket, const QString &message)
{
    //packet preparation
    QByteArray packet;
    QDataStream out(&packet, QIODevice::WriteOnly);

    out << (quint16) 0;
    out << message;
    out.device()->seek(0);
    out << (quint16) (packet.size() - sizeof(quint16));

    //packet sending
    for(int i = 0 ; i < clients.size() ; i++)
    {
        if(clients[i]->GetSocket() != socket)
        {
            clients[i]->SendMessage(packet);
        }
    }
}

Client* ServerWindow::findClient(QTcpSocket *socket)
{
    for(int i = 0 ; i < clients.size() ; i++)
    {
        if(clients[i]->GetSocket() == socket)
        {
            return clients[i];
        }
    }
    return NULL;
}
